import tkinter as tk
from tkinter import ttk, messagebox
import serial
import serial.tools.list_ports
import numpy as np
import math
import binascii
import random
from tkinter import scrolledtext

class SerialCommunicator:
    def __init__(self, root):
        self.root = root
        self.root.title("串口数据发送器")
        self.root.geometry("400x350")

        # 可用串口列表
        self.ports = []
        self.selected_port = tk.StringVar()
        self.selected_baudrate = tk.StringVar(value="921600")
        self.continuous_send = tk.BooleanVar()  # 连续发送标志

        # 创建UI
        self.create_widgets()
        # 更新串口列表
        self.update_port_list()

    def create_widgets(self):
        # 串口选择
        port_frame = ttk.LabelFrame(self.root, text="串口设置")
        port_frame.pack(padx=10, pady=10, fill="x")

        ttk.Label(port_frame, text="选择串口:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.port_combobox = ttk.Combobox(port_frame, textvariable=self.selected_port, state="readonly")
        self.port_combobox.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        port_frame.columnconfigure(1, weight=1)

        refresh_btn = ttk.Button(port_frame, text="刷新", command=self.update_port_list)
        refresh_btn.grid(row=0, column=2, padx=5, pady=5)

        # 波特率选择
        ttk.Label(port_frame, text="波特率:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        baudrate_combobox = ttk.Combobox(port_frame, textvariable=self.selected_baudrate, state="readonly")
        baudrate_combobox['values'] = ["9600", "19200", "38400", "57600", "115200", "230400","921600"]
        baudrate_combobox.grid(row=1, column=1, padx=5, pady=5, sticky="ew")

        # 添加数据类型选择
        data_type_frame = ttk.LabelFrame(self.root, text="数据设置")
        data_type_frame.pack(padx=10, pady=5, fill="x")

        self.data_type = tk.StringVar(value="sine")
        ttk.Radiobutton(data_type_frame, text="正弦波", variable=self.data_type, value="sine").grid(row=0, column=0, padx=10, pady=5)
        ttk.Radiobutton(data_type_frame, text="随机点", variable=self.data_type, value="random").grid(row=0, column=1, padx=10, pady=5)

        self.data_group = tk.StringVar(value="group1")
        ttk.Radiobutton(data_type_frame, text="第一组 (Ad0)", variable=self.data_group, value="group1").grid(row=1, column=0, padx=10, pady=5)
        ttk.Radiobutton(data_type_frame, text="第二组 (Ab1)", variable=self.data_group, value="group2").grid(row=1, column=1, padx=10, pady=5)

        # 连续发送选项
        continuous_frame = ttk.Frame(self.root)
        continuous_frame.pack(padx=10, pady=5, fill="x")
        ttk.Checkbutton(continuous_frame, text="连续发送两组数据", variable=self.continuous_send).pack(anchor="w")

        # 发送按钮
        send_btn = ttk.Button(self.root, text="发送数据", command=self.send_data)
        send_btn.pack(pady=10)

        # 状态标签
        self.status_label = ttk.Label(self.root, text="就绪", foreground="green")
        self.status_label.pack(pady=5)

        # 添加16进制数据显示区域
        ttk.Label(self.root, text="发送数据 (16进制):").pack(pady=5)
        self.hex_display = scrolledtext.ScrolledText(self.root, width=80, height=6, font=('Consolas', 10))
        self.hex_display.pack(pady=5)
        self.hex_display.config(state=tk.DISABLED)

    def update_port_list(self):
        self.ports = [port.device for port in serial.tools.list_ports.comports()]
        self.port_combobox['values'] = self.ports
        if self.ports:
            self.selected_port.set(self.ports[0])
            self.status_label.config(text=f"发现{len(self.ports)}个串口", foreground="green")
        else:
            self.selected_port.set("")
            self.status_label.config(text="未发现串口", foreground="red")

    def generate_sine_wave(self):
        # 生成512个8位正弦波数据
        x = np.linspace(0, random.random() * 5 * math.pi, 256)
        sine_wave = (np.sin(x) * 127 * random.random() + 128)  # 转换为0-255范围并乘以0-1随机系数
        return sine_wave.astype(np.uint8)

    def generate_random_points(self):
        # 生成512个8位随机点数据
        return np.random.randint(0, 256, 256, dtype=np.uint8)

    def send_data(self):
        if not self.selected_port.get():
            messagebox.showerror("错误", "请选择串口")
            return

        try:
            # 创建串口连接
            ser = serial.Serial(
                port=self.selected_port.get(),
                baudrate=int(self.selected_baudrate.get()),
                timeout=1
            )

            # 如果启用连续发送，则发送两组数据
            if self.continuous_send.get():
                # 发送第一组数据
                self.send_single_data(ser, "group1")
                
                # 发送第二组数据
                self.send_single_data(ser, "group2")
                
                self.status_label.config(
                    text="成功发送两组数据",
                    foreground="green"
                )
            else:
                # 发送单组数据
                self.send_single_data(ser, self.data_group.get())
                
                self.status_label.config(
                    text=f"成功发送{len(self.last_sent_data)}字节数据",
                    foreground="green"
                )

            ser.close()

            # 转换为16进制显示
            hex_data = binascii.hexlify(self.last_sent_data).decode('utf-8')
            # 格式化16进制字符串，每两个字符加空格
            formatted_hex = ' '.join([hex_data[i:i+2] for i in range(0, len(hex_data), 2)])

            # 更新16进制显示
            self.hex_display.config(state=tk.NORMAL)
            self.hex_display.delete(1.0, tk.END)
            self.hex_display.insert(tk.END, formatted_hex)
            self.hex_display.config(state=tk.DISABLED)

        except serial.SerialException as e:
            self.status_label.config(
                text=f"串口错误: {str(e)}",
                foreground="red"
            )
        except Exception as e:
            self.status_label.config(
                text=f"错误: {str(e)}",
                foreground="red"
            )

    def send_single_data(self, ser, group):
        # 生成数据
        if group == "group1":
            header = b'A' + b'd0'  # 第一组数据头部
        else:
            header = b'A' + b'd1'  # 第二组数据头部 (Ad1)

        if self.data_type.get() == "sine":
            data_body = self.generate_sine_wave()
        else:
            data_body = self.generate_random_points()

        end_flag = b'\x00\xff\x00\xff\x00\xff'  # 结束标志位
        data = header + data_body.tobytes() + end_flag
        
        # 保存最后一次发送的数据
        self.last_sent_data = data
        
        # 发送数据
        ser.write(data)

if __name__ == "__main__":
    root = tk.Tk()
    app = SerialCommunicator(root)
    root.mainloop()